package org.xjk;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import me.tongfei.progressbar.ProgressBar;
import org.xjk.alg.Alg;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * Hello world!
 *
 */
public class App 
{
    public static JCommander jCommander;
    private static AppConfig config;

    public static void main( String[] args ) throws Exception
    {
//        System.out.println(new File(".").getAbsolutePath());
//        System.exit(-1);

        config = new AppConfig();
        jCommander = JCommander.newBuilder()
                .addObject(config)
                .build();
        jCommander.parse(args);

        //System.out.println(jCommander.getParsedCommand());

        run();
    }

    private static void  run() throws Exception{
        if (config.isHelp()){
            jCommander.usage();
        }else if ("encode".equals(config.getMode())){
            encode();
        }else {
            decode();
        }

    }

    /**
     * 文件加密编码
     */
    private static void encode() throws Exception{
        File inputFile = new File(config.getInputFile());
        File outputFile = new File(config.getOutputFile());


        if (config.getCount()>0){

            List<OutputStream> outputStreams = new ArrayList<>(config.getCount());

            try(InputStream inputStream = new BufferedInputStream(Files.newInputStream(inputFile.toPath()))){
                for (int i = 0; i < config.getCount(); i++) {
                    Path path = Paths.get(outputFile.getAbsolutePath(), inputFile.getName() + "-part" + i + Constant.FILE_SUFFIX);
                    OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(path));
                    outputStreams.add(outputStream);
                }


                System.out.println("start encryption...");
                long seed = Alg.stringToLong(config.getPassword());
                Random random = new Random(seed);
                long available = inputFile.length();

                //创建进度条
                ProgressBar progressBar = new ProgressBar("encryption", available);

                for (int i = 0; ; i++) {
                    int read = inputStream.read();
                    if (read==-1){
                        progressBar.close();
                        break;
                    }
                    int nextIndex = random.nextInt(config.getCount());
                    outputStreams.get(nextIndex).write(read);
                    progressBar.step();
                }

                System.out.println("done!");
                printLog(config.getLogPath());

            }catch (Exception e){
                e.printStackTrace();
            }finally {
                outputStreams.forEach(outputStream -> {
                    try {
                        outputStream.flush();
                        outputStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });



            }


        }else {
            throw new IllegalAccessException("参数[-p]必须大于0");
        }

    }

    /**
     * 文件解密解码
     * @throws Exception
     */
    private static void decode() throws Exception{
        File inputFile = new File(config.getInputFile());
        File outputFile = new File(config.getOutputFile());

        if (!inputFile.isDirectory()){
            throw new IllegalAccessException("decode模式下参数[-i]必须为目录");
        }
        File[] files = inputFile.listFiles();
        HashMap<Integer,File> fileIndexMap= new HashMap<>();

//        原始文件大小
        long available=0;
        for (File file : files) {
            //用正则表达式从文件名中提取“-part”和".sm.part"之前的数字
            String name = file.getName();
            if (name.matches(".*-part\\d+\\.sm\\.part")){
                //System.out.println(name);
                String[] split = name.split("-part");
                String part = split[1].split("\\.sm\\.part")[0];
                int partIndex = Integer.parseInt(part);
                fileIndexMap.put(partIndex,file);
                available+=file.length();
                if (partIndex>=config.getCount()){
                    throw new IllegalAccessException("原始文件数据错误");
                }
            }
        }

        //判断fileIndexMap中index值是否连续
        for (int i = 0; i < config.getCount(); i++) {
            if (!fileIndexMap.containsKey(i)){
                throw new IllegalAccessException("原始文件数据错误");
            }
        }

        if (config.getCount()>0){

            InputStream[] inputStreams = new InputStream[config.getCount()];

            for (Integer index : fileIndexMap.keySet()) {
                inputStreams[index] = new BufferedInputStream(Files.newInputStream(fileIndexMap.get(index).toPath()));

            }

            //创建进度条
            ProgressBar progressBar = new ProgressBar("decryption", available);

            try(OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(outputFile.toPath()))){

                System.out.println("start decryption...");
                Random random = new Random(Alg.stringToLong(config.getPassword()));
                while (true){
                    int readByte = inputStreams[random.nextInt(config.getCount())].read();
                    if (readByte==-1){
                        break;
                    }
                    outputStream.write(readByte);
                    progressBar.step();
                }
                System.out.println("done！");
                progressBar.close();

            }catch (Exception e){
                e.printStackTrace();
            }finally {
                for (InputStream inputStream : inputStreams) {
                    try {
                        inputStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }


        }else {
            throw new IllegalAccessException("参数[-p]必须大于0");
        }
    }


    public static void printLog(String path){
        File file = new File(path);

        try {
            if (!file.exists()){
                file.createNewFile();
            }
            FileWriter writer =new FileWriter(file,true);
            //向writer文件写入时间戳和运行命令及密码
            writer.write(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))+" "+config.getInputFile()+",pwd="+config.getPassword()+"\n");
            writer.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}
